package time // Package time import "xemo.top/docker/docker/api/types/time"
import (
	"fmt"
	"math"
	"strconv"
	"strings"
	"time"
)

// 这些是在Time.Format和Time.Parse中使用的附加预定义布局，其中包含 “docker logs” 和 “docker events” 的 -- sever和 -- 直到参数
// These are additional predefined layouts for use in Time.Format and Time.Parse with --since and --until parameters for `docker logs` and `docker events`
const (
	// RFC3339 with local timezone
	rFC3339Local = "2006-01-02T15:04:05"
	// RFC3339Nano with local timezone
	rFC3339NanoLocal = "2006-01-02T15:04:05.999999999"
	// RFC3339 with time at 00:00:00
	dateWithZone = "2006-01-02Z07:00"
	// RFC3339 with local timezone and time at 00:00:00
	dateLocal = "2006-01-02"
)

// GetTimestamp 尝试将给定的字符串解析为golang持续时间，然后是RFC3339时间，最后是Unix时间戳。如果其中任何一个成功，它将返回Unix时间戳作为字符串，否则返回给定值。在持续时间输入的情况下，返回的时间戳被计算为给定的参考时间减去持续时间的量。
// GetTimestamp tries to parse given string as golang duration,then RFC3339 time and finally as a Unix timestamp.If any of these were successful,it returns a Unix timestamp as string otherwise returns the given value back.In case of duration input,the returned timestamp is computed as the given reference time minus the amount of the duration.
func GetTimestamp(value string, reference time.Time) (string, error) {
	if d, err := time.ParseDuration(value); value != "0" && err == nil {
		return strconv.FormatInt(reference.Add(-d).Unix(), 10), nil
	}
	var format string
	// 如果字符串具有Z或a或三个破折号，则使用parse，否则使用parseinlocation
	// if the string has a Z or a + or three dashes use parse otherwise use parseinlocation
	parseInLocation := !(strings.ContainsAny(value, "zZ+") || strings.Count(value, "-") == 3)
	if strings.Contains(value, ".") {
		if parseInLocation {
			format = rFC3339NanoLocal
		} else {
			format = time.RFC3339Nano
		}
	} else if strings.Contains(value, "T") {
		// 我们想要时间戳的T部分中的冒号数
		// we want the number of colons in the T portion of the timestamp
		tcolons := strings.Count(value, ":")
		// 如果parseInLocation关闭，我们有一个/-区域偏移 (不是Z)，那么在tz偏移的输入中将有一个额外的冒号从tcolons计数中减去该冒号
		// if parseInLocation is off and we have a +/- zone offset (not Z) then there will be an extra colon in the input for the tz offset subtract that colon from teh tcolons count
		if !parseInLocation && !strings.ContainsAny(value, "zZ") && tcolons > 0 {
			tcolons--
		}
		if parseInLocation {
			switch tcolons {
			case 0:
				format = "2006-01-02T15"
			case 1:
				format = "2006-01-02T15:04"
			default:
				format = rFC3339Local
			}
		} else {
			switch tcolons {
			case 0:
				format = "2006-01-02T15Z07:00"
			case 1:
				format = "2006-01-02T15:04Z07:00"
			default:
				format = time.RFC3339
			}
		}
	} else if parseInLocation {
		format = dateLocal
	} else {
		format = dateWithZone
	}
	var t time.Time
	var err error
	if parseInLocation {
		t, err = time.ParseInLocation(format, value, time.FixedZone(reference.Zone()))
	} else {
		t, err = time.Parse(format, value)
	}
	if err != nil {
		// if there is a `-` then it's an RFC3339 like timestamp
		if strings.Contains(value, "-") {
			return "", err // was probably an RFC3339 like timestamp but the parser failed with an error
		}
		if _, _, err := parseTimestamp(value); err != nil {
			return "", fmt.Errorf("failed to parse value as time or duration: %q", value)
		}
		return value, nil // unix timestamp in and out case (meaning: the value passed at the command line is already in the right format for passing to the server)
	}

	return fmt.Sprintf("%d.%09d", t.Unix(), int64(t.Nanosecond())), nil
}
func ParseTimestamps(value string, def int64) (int64, int64, error) {
	if value == "" {
		return def, 0, nil
	}
	return parseTimestamp(value)
}
func parseTimestamp(value string) (int64, int64, error) {
	sa := strings.SplitN(value, ".", 2)
	s, err := strconv.ParseInt(sa[0], 10, 64)
	if err != nil {
		return s, 0, err
	}
	if len(sa) != 2 {
		return s, 0, nil
	}
	n, err := strconv.ParseInt(sa[1], 10, 64)
	if err != nil {
		return s, n, err
	}
	// 应该已经以纳秒为单位，但以防万一将n转换为纳秒
	n = int64(float64(n) * math.Pow(float64(10), float64(9-len(sa[1]))))
	return s, n, nil
}
